#include "AXP202.h"

// "&" 与位运算置位，"|" 或位运算写入

/* Private functions （在类内判断数字大中小。主要是为了限制设置电压时输入超出范围，incline定义快速读取）*/
inline uint16_t AXP202::_getMin(uint16_t a, uint16_t b) {
    return ((a)<(b)?(a):(b));
}

inline uint16_t AXP202::_getMax(uint16_t a, uint16_t b) {
    return ((a)>(b)?(a):(b));
}

inline uint16_t AXP202::_getMid(uint16_t input, uint16_t min, uint16_t max) {
    return _getMax(_getMin(input, max), min);
}

/* Public functions (包含IIC的初始化以及是否初始化的判断)*/
#ifdef ARDUINO
bool AXP202::begin(TwoWire * wire)
{
    _I2C_init(wire, AXP202_ADDR);
    return _I2C_checkDevAvl();
}
#else
void AXP202::begin()
{
/* 各种电压设置与ADC使能一类可以写在这里 */
}
#endif

/* 输入电源状态寄存器（地址：0x00）
 * 函数写法功能解析：
 *  首先判断从输入电源状态寄存器读取的8bit值（由高到低读取7-->0）与0Bxxxxxxxx进行与运算，若两者相同则输出则为true反之为false
 * 再判断如下语句：  ("true" or" false") ? true ：false;   意为：若条件为true则返回1,反之返回0
 */
bool AXP202::isVBUSExist()
{
    return ( _I2C_read8Bit(0x00) & 0B00100000 ) ? true : false;
}

bool AXP202::isVBUSAvl()
{
    return ( _I2C_read8Bit(0x00) & 0B00010000 ) ? true : false;
}

bool AXP202::getBatCurrentDir()
{
    return ( _I2C_read8Bit(0x00) & 0B00000100 ) ? true : false;
}

/* 电源工作模式以及充电状态指示寄存器（地址：0x01）
 */
bool AXP202::isOverTemp()
{
    return ( _I2C_read8Bit(0x01) & 0B10000000 ) ? true : false;
}

bool AXP202::isCharging()
{
    return ( _I2C_read8Bit(0x01) & 0B01000000 ) ? true : false;
}

bool AXP202::isBatExist()
{
    return ( _I2C_read8Bit(0x01) & 0B00100000 ) ? true : false;
}

bool AXP202::isBatAct()
{
    return ( _I2C_read8Bit(0x01) & 0B00001000 ) ? true : false;
}

bool AXP202::isChargeCsmaller()
{
    return ( _I2C_read8Bit(0x01) & 0B00000100 ) ? true : false;
}

/* 电源输出控制寄存器（地址：0x12）
 * 函数作用：开关某一通道电源输出
 * 电源输出电压配置寄存器
 * DC-DC2     0x23  0.7-2.275V  25mV/step    7-6bit(stable)   5-0bit(usage)
 * DC-DC3     0x27  0.7-3.5V    25mV/step    7bit(stable)     6-0bit(usage)
 * LDO2&LDO4  0x28  1.8-3.3V    100mV/step   None(stable)     7-4bit&3-0bit(usage)
 * LDO3       0x29  0.7-2.275V  25mV/step    7bit(stable)     6-0bit(usage)
 * 
 * 函数写法功能解析：_getMid()可以避免用户输入过大或者过小的值导致程序意外错误，输入过小值直接
 * 输出最小电压，过大值直接输出最大电压。然后将用户输入值转化为对应的电压乘数（step）
 * (buff & 0B10000000)：将buff转为八位二进制,重置电压设置位0-6bit,"维持保留位7bit" !!!
 * (voltage & 0B01111111)：将voltage转为八位二进制,维持待写入电压位0-6bit，"重置保留位7bit" !!!
 * (buff & 0B10000000) | (voltage & 0B01111111)：最后的或运算结束后，只有0-6bit改变了，7bit还仍
 * 然维持读取时的状态，起到了不更改保留位但却更改了电压位的作用！！！
 */
void AXP202::setOutputEnable(OUTPUT_CHANNEL channel, bool state)
{
    uint8_t buff = _I2C_read8Bit(0x12); //buff类型为unsigned char
    buff = state ? ( buff | (1U << channel) ) : ( buff & ~(1U << channel) );
    _I2C_write1Byte(0x12, buff);        //对0x12寄存器写入1字节也就是8位二进制buff
}

void AXP202::setOutputVoltage(OUTPUT_CHANNEL channel, uint16_t voltage)
{
    uint8_t buff = 0;
    switch (channel) {
        case OP_DCDC2:
            voltage = (_getMid(voltage, 700, 2275) - 700) / 25; //0 - 112(step)
            buff = _I2C_read8Bit(0x23);
            buff = (buff & 0B11000000) | (voltage & 0B00111111);
            _I2C_write1Byte(0x23, buff);
            break;
        case OP_DCDC3:
            voltage = (_getMid(voltage, 700, 3500) - 700) / 25;
            buff = _I2C_read8Bit(0x27);
            buff = (buff & 0B10000000) | (voltage & 0B01111111);
            _I2C_write1Byte(0x27, buff);
            break;
        case OP_LDO2:
            voltage = (_getMid(voltage, 1800, 3300) - 1800) / 100;
            buff = _I2C_read8Bit(0x28);
            buff = (buff & 0B00001111) | (voltage << 4);
            _I2C_write1Byte(0x28, buff);
            break;
        case OP_LDO3:
            voltage = (_getMid(voltage, 700, 2275) - 700) / 25;
            buff = _I2C_read8Bit(0x29);
            buff = (buff & 0B10000000) | (voltage & 0B01111111);
            _I2C_write1Byte(0x29, buff);
            break;
        case OP_LDO4:
            voltage = (_getMid(voltage, 1800, 3300) - 1800) / 100;
            buff = _I2C_read8Bit(0x28);
            buff = (buff & 0B11110000) | (voltage);
            _I2C_write1Byte(0x28, buff);
            break;
        default:
            break;
    }
}

/* 开关芯片控制寄存器（地址：0x32）
 * 函数作用：开关芯片输出
 * 
 * 函数写法功能解析：给该寄存器7bit位写 "1" 会关闭芯片所有输出，为了不改变该寄存器的其它
 * 位设置，让二进制形式仅对7bit写一"0B1000 0000"和读取到的原寄存器状态做 "|" 或位运算即
 * 可。由于关机后该位上电会自动置 "0",因此更改时可以不使用 "&" 与位运算重置该位.
 */
void AXP202::powerOFF(void)
{
    _I2C_write1Byte(0x32, (_I2C_read8Bit(0x32) | 0B10000000));
}

bool AXP202::powerState(void)
{
    return ( _I2C_read8Bit(0x32) & 0B10000000 ) ? false : true;
}

/* 长按按键芯片开关机时间设置寄存器（地址：0x36）
 * 函数作用：设置长按按键芯片开关机时间
 * 
 * 函数写法功能解析："&" 运算先将 "4 and 5 bit" 置位，然后保留其它位已经写 "1" 的配置，
 * 最后 "|" 运算对 "4 and 5 bit" 写"入 " 0 or 1 "
 */
void AXP202::setPowerOnTime(POWERON_TIME onTime)
{
    _I2C_write1Byte(0x36, ((_I2C_read8Bit(0x36) & 0B00111111) | onTime));
}

void AXP202::setPowerOffTime(POWEROFF_TIME offTime)
{
    _I2C_write1Byte(0x36, ((_I2C_read8Bit(0x36) & 0B11111100) | offTime));
}

/* 充电控制寄存器1（地址：0x33）
 * 函数作用：设置充电电流以及是否使能充电功能，充电目标电压(5 and 6 bit)默认为4.2V(1 and 0)
 * 
 * 函数写法功能解析：同上 "&" 与位运算置位，"|" 或位运算写入
 */
void AXP202::setChargeEnable(bool state)
{
    if (state)
        _I2C_write1Byte(0x33, ((_I2C_read8Bit(0x33) | 0B10000000)));
    else
        _I2C_write1Byte(0x33, ((_I2C_read8Bit(0x33) & 0B01111111)));
}

void AXP202::setChargeCurrent(CHARGE_CURRENT current)
{
    _I2C_write1Byte(0x33, ((_I2C_read8Bit(0x33) & 0B11110000) | current));
}

/* ADC使能寄存器1（地址：0x82）
 * 函数返回值：None
 * 函数作用：设置ADC使能
 */
void AXP202::setADCEnable(ADC_CHANNEL channel, bool state)
{
    uint8_t buff = _I2C_read8Bit(0x82);
    buff = state ? ( buff | (1U << channel) ) : ( buff & ~(1U << channel) );
    _I2C_write1Byte(0x82, buff);
}

/* ADC使能寄存器2（地址：0x83）
 * 函数返回值：None
 * 函数作用：设置芯片温度检测ADC使能&GPIO的ADC使能
 */
void AXP202::setChipTempEnable(bool state)
{
    uint8_t buff = _I2C_read8Bit(0x83);
    buff = state ? ( buff | 0B10000000 ) : ( buff & 0B01111111 );
    _I2C_write1Byte(0x83, buff);
}

void AXP202::setGPIO0ADCEnable(bool state)
{
    uint8_t buff = _I2C_read8Bit(0x83);
    buff = state ? ( buff | 0B00001000 ) : ( buff & 0B11110111 );
    _I2C_write1Byte(0x83, buff);
}

void AXP202::setGPIO1ADCEnable(bool state)
{
    uint8_t buff = _I2C_read8Bit(0x83);
    buff = state ? ( buff | 0B00000100 ) : ( buff & 0B11111011 );
    _I2C_write1Byte(0x83, buff);
}

/* 以上为设置寄存器数据 */
/* 以下为读取寄存器数据 */

//返回高八位 + 低四位电池电压   地址：高0x78 低0x79 精度：1.1mV
float AXP202::getBatVoltage()
{
    float ADCLSB = 1.1 / 1000.0;
    return _I2C_read12Bit(0x78) * ADCLSB;
}

//返回高八位 + 低五位电池电流   地址：充电电流（高0x7A 低0x7B） & 放电电流（高0x7C 低0x7D） 精度：0.5mA
float AXP202::getBatCurrent()
{
    float ADCLSB = 0.5;
    uint16_t CurrentIn = _I2C_read13Bit(0x7A);
    uint16_t CurrentOut = _I2C_read13Bit(0x7C);
    return (CurrentIn - CurrentOut) * ADCLSB;
}

//返回高八位 + 中八位 + 低八位电池瞬时功率  地址：高0x70 中0x71 低0x72 数据乘以精度减小误差
float AXP202::getBatPower()
{
    float VoltageLSB = 1.1;
    float CurrentLCS = 0.5;
    uint32_t ReData = _I2C_read24Bit(0x70);
    return VoltageLSB * CurrentLCS * ReData / 1000.0;    
}

//返回高八位 + 低四位USB输入电压   地址：高0x5A 低0x5B  精度：1.7mV
float AXP202::getVBUSVoltage()
{
    float ADCLSB = 1.7 / 1000.0; 
    uint16_t ReData = _I2C_read12Bit(0x5A);
    return ReData * ADCLSB;
}

//返回高八位 + 低四位USB输入电流   地址：高0x5C 低0x5D  精度：0.375mA
float AXP202::getVBUSCurrent()
{
    float ADCLSB = 0.375;
    uint16_t ReData = _I2C_read12Bit(0x5C);
    return ReData * ADCLSB;
}

//返回高八位 + 低四位芯片内置温度传感器温度 地址：高0x5E 低0x5F 精度：0.1℃  最小值-144.7℃
float AXP202::getAXP202Temp()
{
    float ADCLSB = 0.1;
    const float OFFSET_DEG_C = -144.7;
    uint16_t ReData = _I2C_read12Bit(0x5E);
    return OFFSET_DEG_C + ReData * ADCLSB;
}

void AXP202::initIRQState(void)
{
    _I2C_write1Byte(0x40, ((_I2C_read8Bit(0x40) & 0B00000001) | 0B00000000));
    _I2C_write1Byte(0x41, ((_I2C_read8Bit(0x41) & 0B00000000) | 0B00000000));
    _I2C_write1Byte(0x42, ((_I2C_read8Bit(0x42) & 0B00100000) | 0B00000000));
    _I2C_write1Byte(0x43, ((_I2C_read8Bit(0x43) & 0B00000000) | 0B00000000));
    _I2C_write1Byte(0x4A, ((_I2C_read8Bit(0x44) & 0B00010000) | 0B00000000));
}

/* 按键状态检测 */
void AXP202::aoToPowerOFFEnabale(void)
{
    _I2C_write1Byte(0x36, (_I2C_read8Bit(0x36) | 0B00001000));
}

bool AXP202::getShortPressIRQState(void)
{
    return ( _I2C_read8Bit(0x4A) & 0B00000010 ) ? true : false;
}

void AXP202::setLongPressTime(LONG_PRESS_TIME pressTime)
{
    _I2C_write1Byte(0x36, ((_I2C_read8Bit(0x36) & 0B11001111) | pressTime));
}

bool AXP202::getLongPressIRQState(void)
{
    return ( _I2C_read8Bit(0x42) & 0B00000001 ) ? true : false;
}

void AXP202::initKeyPressIRQ(LONG_PRESS_TIME pressTime)
{
    initIRQState();
    aoToPowerOFFEnabale();
    setLongPressTime(pressTime);
}

void AXP202::setShortPressIRQDisabale(void)
{
    _I2C_write1Byte(0x46, (_I2C_read8Bit(0x42) | 0B00000010));
}

void AXP202::setLongPressIRQDisabale(void)
{
    _I2C_write1Byte(0x46, (_I2C_read8Bit(0x42) | 0B00000001));
}

AXP202 pmu;